package com.spring.framework.config.autowired.model;

import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * 根据上面的@Autowired的规则，我们发现，即使设置了required=false，只要有一个依赖项不能注入，那么该构造器就不会使用。为此，我们必须将可能的构造
 * 器参数组合都列出来全部作为候选构造器，才能最终实现“有就注入，没有就不注入”的功能，非常麻烦。
 * <p>
 * 现在，我们可以使用Java的Optional来实现真正的“有就注入，没有就不注入”的功能。关于Optional类，在Java 8 lambda的文章中有详细描述，它是Java8新
 * 增的一个类，表示可能包含或不包含非空值的容器对象，用来防止空指针异常。
 *
 * @author xuweizhi
 * @since 2020/12/15 11:14
 */
@Component
public class AutowiredConstructorOptionalDemo {

	private OptionalDemoA optionalDemoA;

	private OptionalDemoB optionalDemoB;

	/**
	 * 可以看到，最终调用了无参构造器的方法，optionalDemoA的依赖虽然在容器中，但是也没有注入进来，仅仅是因为optionalDemoB的依赖不在容器中，并且如果
	 * 我们不提供无参构造器还会抛出异常。
	 */
	//@Autowired(required = false)
	//public AutowiredConstructorOptionalDemo(OptionalDemoA optionalDemoA, OptionalDemoB optionalDemoB) {
	//	System.out.println("optionalDemoA" + "optionalDemoB");
	//	this.optionalDemoA = optionalDemoA;
	//	this.optionalDemoB = optionalDemoB;
	//}

	//public AutowiredConstructorOptionalDemo() {
	//	System.out.println("无参");
	//}

	/**
	 * 我们发现，不但没有报错，而且IoC容器中存在的依赖OptionalDemoA也注入进来了，不存在的依赖则默认为null，这样才是真正符合我们的“有就注入，没有就不
	 * 注入”的功能，而且实现的非常简单！
	 * <p>
	 * 我们可以对非必需的依赖都使用Optional包装，表示该项依赖是非必需的。实际上，这可以看作装饰设计模式的应用，Spring无论找没找到对应的依赖，都会将返
	 * 回值分别使用一个Optional对象包装。这样，就是返回null，但是Optional对象不为null，因此不会报错。
	 * <p>
	 * Optional还会抵消required = true带来的强制依赖注入非null检查。即，即使没有这个依赖项并且required=true，但是如果使用Optional包装依赖参数的类
	 * 型，那么永远不会抛出异常。因此，对于必须依赖项，不建议使用Optional包装！对于非必须依赖项，则建议使用Optional包装！
	 */
	public AutowiredConstructorOptionalDemo(Optional<OptionalDemoA> optionalDemoA,
											Optional<OptionalDemoB> optionalDemoB) {
		System.out.println("optionalDemoA" + "optionalDemoB");
		optionalDemoA.ifPresent(i -> this.optionalDemoA = i);
		optionalDemoB.ifPresent(i -> this.optionalDemoB = i);
	}

	@Component("optionalDemoA")
	public static class OptionalDemoA {
		public OptionalDemoA() {
			System.out.println("OptionalDemoA：" + this);
		}
	}

	//@Component("optionalDemoB")
	public static class OptionalDemoB extends OptionalDemoA {
		public OptionalDemoB() {
			System.out.println("OptionalDemoB：" + this);
		}
	}

	@Override
	public String toString() {
		return "AutowiredConstructorOptionalDemo{" +
				"optionalDemoA=" + optionalDemoA +
				", optionalDemoB=" + optionalDemoB +
				'}';
	}
}

